昨天提到,每個 process 都有自己的虛擬位址空間。不過 kernel 不會把整個位址空間當成一大塊平面來管理。它會把有意義的區間拆成多個 VMA,也就是 Virtual Memory Area。每個 VMA 描述一段連續的虛擬位址範圍,以及這段範圍可以怎麼被使用。
可以把 VMA 想成 process 位址空間裡的地籍資料。某一段是可執行的程式碼,某一段是可讀寫的 heap,某一段是 stack,某一段來自 shared library,某一段則是 mmap() 映射進來的檔案。kernel 不只記錄起點和終點,也會記錄權限,例如 readable、writable、executable,以及這段區域是否能共享。
在 Linux 上,可以藉由 /proc/<pid>/maps 看到這些區間。每一行大致對應一個 VMA,裡面會有位址範圍、權限、offset、裝置、inode 和檔名。看到 [heap]、[stack] 或某個 .so 檔案時,其實就是在看 process 的位址空間如何被切成不同用途。
mmap() 是理解 VMA 很重要的入口。它可以把檔案映射到記憶體,也可以建立 anonymous mapping。檔案映射常見於載入 shared library,或讓程式像操作記憶體一樣讀檔。anonymous mapping 則常被 allocator 拿來配置大塊記憶體。不管是哪一種,最後都會讓 process 多出一段新的 VMA。
這裡有一個容易混淆的點:建立 VMA 不代表立刻配置實體 RAM。呼叫 mmap() 成功後,kernel 可能只是先建立這段虛擬位址範圍的描述。等 process 第一次讀寫某個 page,觸發 page fault,kernel 才真的決定要從檔案載入資料、配置匿名頁面,或回報權限錯誤。
因此,VMA 是「這段位址應該怎麼處理」的規則,不是「這段位址已經佔了多少 RAM」的直接答案。真正有多少頁面在 RAM 裡,要再看 page table、RSS、page cache 和 reclaim 狀態。
下一篇會進入 page table。VMA 告訴 kernel 一段虛擬位址的規則,但 CPU 執行指令時還需要更細的轉換資料。虛擬位址要能真的讀寫,最後還是得靠 page table 把它對應到實體頁面。